/*
* This file is a part of the open-eBackup project.
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
*
* Copyright (c) [2024] Huawei Technologies Co.,Ltd.
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*/
#include "gtest/gtest.h"
#include "../llt_stub/named_stub.h"
#include "gmock/gmock.h"
#include "gmock/gmock-actions.h"
#include "mockcpp/mockcpp.hpp"
#include "ObjectStorageIndexJob.h"
#include "client/ClientInvoke.h"
#include "PluginUtilities.h"

using namespace std;
using namespace AppProtect;
using namespace OBSPlugin;

namespace {
    const int ENDPOINT_PORT = 8088;
}

class Scanner_test_Index : public Scanner {
public:
    explicit Scanner_test_Index(const ScanConfig& scanConfig);
    ~Scanner_test_Index() {};

    SCANNER_STATUS Start() override;
    SCANNER_STATUS Abort()override;
    SCANNER_STATUS Destroy() override;
    SCANNER_STATUS Enqueue(const std::string& directory, const std::string& prefix = "",
                           uint8_t filterFlag = 0) override;
    SCANNER_STATUS EnqueueV2(const std::string& directory) override;
    SCANNER_STATUS GetStatus() override;
    ScanStatistics GetStatistics() override;
    ErrRecorder QueryFailure() override;

protected:
    ScanConfig m_config;
};

class Scanner_test_Index_Abort : public Scanner {
public:
    explicit Scanner_test_Index_Abort(const ScanConfig& scanConfig);
    ~Scanner_test_Index_Abort() {};

    SCANNER_STATUS Start() override;
    SCANNER_STATUS Abort()override;
    SCANNER_STATUS Destroy() override;
    SCANNER_STATUS Enqueue(const std::string& directory, const std::string& prefix = "",
                           uint8_t filterFlag = 0) override;
    SCANNER_STATUS EnqueueV2(const std::string& directory) override;
    SCANNER_STATUS GetStatus() override;
    ScanStatistics GetStatistics() override;
    ErrRecorder QueryFailure() override;

protected:
    ScanConfig m_config;
};

class Scanner_test_Index_Failed : public Scanner {
public:
    explicit Scanner_test_Index_Failed(const ScanConfig& scanConfig);
    ~Scanner_test_Index_Failed() {};

    SCANNER_STATUS Start() override;
    SCANNER_STATUS Abort()override;
    SCANNER_STATUS Destroy() override;
    SCANNER_STATUS Enqueue(const std::string& directory, const std::string& prefix = "",
                           uint8_t filterFlag = 0) override;
    SCANNER_STATUS EnqueueV2(const std::string& directory) override;
    SCANNER_STATUS GetStatus() override;
    ScanStatistics GetStatistics() override;
    ErrRecorder QueryFailure() override;

protected:
    ScanConfig m_config;
};

Scanner_test_Index::Scanner_test_Index(const ScanConfig& scanConfig) : Scanner(scanConfig) {}
SCANNER_STATUS Scanner_test_Index::Start()
{
    return SCANNER_STATUS::SUCCESS;
}
SCANNER_STATUS Scanner_test_Index::Abort()
{
    return SCANNER_STATUS::SUCCESS;
}
SCANNER_STATUS Scanner_test_Index::Destroy()
{
    return SCANNER_STATUS::SUCCESS;
}
SCANNER_STATUS Scanner_test_Index::Enqueue(const std::string& directory, const std::string& prefix, uint8_t filterFlag)
{
    return SCANNER_STATUS::SUCCESS;
}
SCANNER_STATUS Scanner_test_Index::EnqueueV2(const std::string& directory)
{
    return SCANNER_STATUS::SUCCESS;
}
SCANNER_STATUS Scanner_test_Index::GetStatus()
{
    return SCANNER_STATUS::COMPLETED;
}
ScanStatistics Scanner_test_Index::GetStatistics()
{
    ScanStatistics scanStatistics;
    return scanStatistics;
}

ErrRecorder Scanner_test_Index::QueryFailure() {
    ErrRecorder errRecorder {};
    return errRecorder;
}
static unique_ptr<Scanner> CreateScanInstStub(ScanConfig scanConfig)
{
    ScanConfig xx;
    return make_unique<Scanner_test_Index>(xx);
}

Scanner_test_Index_Abort::Scanner_test_Index_Abort(const ScanConfig& scanConfig) : Scanner(scanConfig)
{}
SCANNER_STATUS Scanner_test_Index_Abort::Start()
{
    return SCANNER_STATUS::SUCCESS;
}
SCANNER_STATUS Scanner_test_Index_Abort::Abort()
{
    return SCANNER_STATUS::SUCCESS;
}
SCANNER_STATUS Scanner_test_Index_Abort::Destroy()
{
    return SCANNER_STATUS::SUCCESS;
}
SCANNER_STATUS Scanner_test_Index_Abort::Enqueue(const std::string& directory,
                                                 const std::string& prefix, uint8_t filterFlag)
{
    return SCANNER_STATUS::SUCCESS;
}
SCANNER_STATUS Scanner_test_Index_Abort::EnqueueV2(const std::string& directory)
{
    return SCANNER_STATUS::SUCCESS;
}
SCANNER_STATUS Scanner_test_Index_Abort::GetStatus()
{
    return SCANNER_STATUS::ABORTED;
}
ScanStatistics Scanner_test_Index_Abort::GetStatistics()
{
    ScanStatistics scanStatistics;
    return scanStatistics;
}
ErrRecorder Scanner_test_Index_Abort::QueryFailure() {
    ErrRecorder errRecorder {};
    return errRecorder;
}

Scanner_test_Index_Failed::Scanner_test_Index_Failed(const ScanConfig& scanConfig) : Scanner(scanConfig)
{}
SCANNER_STATUS Scanner_test_Index_Failed::Start()
{
    return SCANNER_STATUS::SUCCESS;
}
SCANNER_STATUS Scanner_test_Index_Failed::Abort()
{
    return SCANNER_STATUS::SUCCESS;
}
SCANNER_STATUS Scanner_test_Index_Failed::Destroy()
{
    return SCANNER_STATUS::SUCCESS;
}
SCANNER_STATUS Scanner_test_Index_Failed::Enqueue(const std::string& directory, const std::string& prefix,
                                                  uint8_t filterFlag)
{
    return SCANNER_STATUS::SUCCESS;
}
SCANNER_STATUS Scanner_test_Index_Failed::EnqueueV2(const std::string& directory)
{
    return SCANNER_STATUS::SUCCESS;
}
SCANNER_STATUS Scanner_test_Index_Failed::GetStatus()
{
    return SCANNER_STATUS::PROTECTED_SERVER_NOT_REACHABLE;
}
ScanStatistics Scanner_test_Index_Failed::GetStatistics()
{
    ScanStatistics scanStatistics;
    return scanStatistics;
}

ErrRecorder Scanner_test_Index_Failed::QueryFailure() {
    ErrRecorder errRecorder {};
    return errRecorder;
}

class ObjectStorageIndexJobTest : public testing::Test {
public:
    void SetUp();
    void TearDown();
    static void SetUpTestCase();
    static void TearDownTestCase();
    void SetJobInfo();
    void SetIncJobInfo();
    LLTSTUB::Stub stub;
    ObjectStorageIndexJob m_indexObj;
};

void ObjectStorageIndexJobTest::SetUpTestCase()
{}

void ObjectStorageIndexJobTest::TearDownTestCase()
{}

static StorageRepository GetCacheRepo()
{
    string path = "/MetaFS/cache";
    HostAddress hostadd;
    hostadd.ip="10.28.12.144";
    StorageRepository cacheRepo;
    cacheRepo.repositoryType = RepositoryDataType::type::CACHE_REPOSITORY;
    cacheRepo.path.push_back(path);
    cacheRepo.remotePath = "/MetaFS/cache";
    cacheRepo.remoteHost.push_back(hostadd);
    cacheRepo.auth.authkey = "admin";
    cacheRepo.auth.authPwd = "Admin@123";
    cacheRepo.endpoint.ip = "10.28.12.144";
    cacheRepo.endpoint.port = ENDPOINT_PORT;

    return cacheRepo;
}

static bool GetDirListInDirectoryStub_Succ(std::string dir, std::vector<string>& fileList)
{
    string controlFile1 = "bucket1";
    string controlFile2 = "bucket2";
    string controlFile3 = "bucket3";
    fileList.push_back(controlFile1);
    fileList.push_back(controlFile2);
    fileList.push_back(controlFile3);
    return true;
}

static StorageRepository GetDataRepo()
{
    HostAddress hostadd;
    hostadd.ip="10.28.12.144";
    StorageRepository dataRepo;
    dataRepo.repositoryType = RepositoryDataType::type::DATA_REPOSITORY;
    dataRepo.remotePath = "/BackupFS";
    dataRepo.path.push_back(dataRepo.remotePath);
    dataRepo.remoteHost.push_back(hostadd);
    dataRepo.auth.authkey = "admin";
    dataRepo.auth.authPwd = "Admin@123";
    dataRepo.endpoint.ip = "10.28.12.144";
    dataRepo.endpoint.port = ENDPOINT_PORT;
    dataRepo.extendInfo = R"({"isCurrentCopyRepo": true, "timestamp": 123, "copyId": "123", "fsId":"123"})";

    return dataRepo;
}

static StorageRepository GetDataRepoPre()
{
    HostAddress hostadd;
    hostadd.ip="10.28.12.144";
    StorageRepository dataRepoPre;
    dataRepoPre.repositoryType = RepositoryDataType::type::DATA_REPOSITORY;
    dataRepoPre.remotePath = "/BackupFS";
    dataRepoPre.path.push_back("/BackupFS");
    dataRepoPre.remoteHost.push_back(hostadd);
    dataRepoPre.auth.authkey = "admin";
    dataRepoPre.auth.authPwd = "Admin@123";
    dataRepoPre.endpoint.ip = "10.28.12.144";
    dataRepoPre.endpoint.port = ENDPOINT_PORT;
    dataRepoPre.extendInfo = R"({"isCurrentCopyRepo": false, "timestamp": 123, "copyId": "123", "fsId":"123"})";

    return dataRepoPre;
}

static StorageRepository GetMetaRepo()
{
    HostAddress hostadd;
    hostadd.ip="10.28.12.144";
    StorageRepository metaRepo;
    metaRepo.repositoryType = RepositoryDataType::type::META_REPOSITORY;
    string path = "/MetaFS/meta";
    metaRepo.path.push_back(path);
    metaRepo.remotePath = "/MetaFS/meta";
    metaRepo.remoteHost.push_back(hostadd);
    metaRepo.auth.authkey = "admin";
    metaRepo.auth.authPwd = "Admin@123";
    metaRepo.endpoint.ip = "10.28.12.144";
    metaRepo.endpoint.port = ENDPOINT_PORT;
    metaRepo.extendInfo = R"({"isCurrentCopyRepo": true, "timestamp": 123, "copyId": "123", "fsId":"123"})";

    return metaRepo;
}

static StorageRepository GetMetaRepoPre()
{
    HostAddress hostadd;
    hostadd.ip="10.28.12.144";
    StorageRepository metaRepoPre;
    metaRepoPre.repositoryType = RepositoryDataType::type::META_REPOSITORY;
    string path = "/MetaFS/meta";
    metaRepoPre.path.push_back(path);
    metaRepoPre.remotePath = "/MetaFS/meta";
    metaRepoPre.remoteHost.push_back(hostadd);
    metaRepoPre.auth.authkey = "admin";
    metaRepoPre.auth.authPwd = "Admin@123";
    metaRepoPre.endpoint.ip = "10.28.12.144";
    metaRepoPre.endpoint.port = ENDPOINT_PORT;
    metaRepoPre.extendInfo = R"({"isCurrentCopyRepo": false, "timestamp": 123, "copyId": "123", "fsId":"123"})";

    return metaRepoPre;
}

static StorageRepository GetIndexRepo()
{
    StorageRepository indexRepo;
    indexRepo.repositoryType = RepositoryDataType::type::INDEX_REPOSITORY;
    string path = "/MetaFS/meta";
    indexRepo.path.push_back(path);
    indexRepo.remotePath = "/MetaFS/meta";

    HostAddress hostadd;
    hostadd.ip="10.28.12.144";
    indexRepo.remoteHost.push_back(hostadd);
    indexRepo.auth.authkey = "admin";
    indexRepo.auth.authPwd = "Admin@123";
    indexRepo.endpoint.ip = "10.28.12.144";
    indexRepo.endpoint.port = ENDPOINT_PORT;

    return indexRepo;
}

static BuildIndexJob BuildIndexJobSetup()
{
    BuildIndexJob buildIndexJob;
    buildIndexJob.requestId = "reqId123";
    buildIndexJob.jobId = "jId123";

    StorageRepository cacheRepo = GetCacheRepo();
    StorageRepository dataRepo = GetDataRepo();
    StorageRepository metaRepo = GetMetaRepo();
    StorageRepository indexRepo = GetIndexRepo();

    Copy copy;
    copy.repositories.push_back(cacheRepo);
    copy.repositories.push_back(dataRepo);
    copy.repositories.push_back(metaRepo);
    std::vector<PrefixInfo> prefix_esn1 {
            {"bucket1", "/opt/aa", {}, true},
            {"bucket2", "/opt/aa", {"11/44"}, false}
    };
   
    BackupObjectInfosInCopy backupObjectInfosInCopy;
    BackupObjectInfo obj1;
    obj1.esn = "esn1";
    obj1.prefixInfo = std::move(prefix_esn1);
    backupObjectInfosInCopy.objectInfos.emplace_back(obj1);
    Module::JsonHelper::StructToJsonString(backupObjectInfosInCopy, copy.extendInfo);
    
    buildIndexJob.copies.push_back(copy);
    buildIndexJob.repositories.push_back(indexRepo);

    buildIndexJob.extendInfo = R"({
    "dstPath": "/opt",
    "fileSystemShareInfo": [
        {
            "accessPermission": 1,
            "advanceParams": {
                "clientName": "*",
                "clientType": 0,
                "portSecure": 1,
                "rootSquash": 1,
                "squash": 1
            },
            "fileSystemName": "fileset_mount_202207251733",
            "type": 1
        }
    ],
    "performance": {}
    })";
    return buildIndexJob;
}

static BuildIndexJob BuildIndexJobSetupInc()
{
    BuildIndexJob buildIndexJob;
    buildIndexJob.requestId = "reqId123";
    buildIndexJob.jobId = "jId123";

    StorageRepository cacheRepo = GetCacheRepo();
    StorageRepository dataRepo = GetDataRepo();
    StorageRepository dataRepoPre = GetDataRepoPre();
    StorageRepository metaRepo = GetMetaRepo();
    StorageRepository metaRepoPre = GetMetaRepoPre();
    StorageRepository indexRepo = GetIndexRepo();

    Copy copy;
    copy.repositories.push_back(cacheRepo);
    copy.repositories.push_back(dataRepo);
    copy.repositories.push_back(metaRepo);
    copy.repositories.push_back(metaRepoPre);
    copy.repositories.push_back(dataRepoPre);

    buildIndexJob.copies.push_back(copy);
    buildIndexJob.repositories.push_back(indexRepo);

    buildIndexJob.extendInfo = R"({
    "dstPath": "/opt",
    "fileSystemShareInfo": [
        {
            "accessPermission": 1,
            "advanceParams": {
                "clientName": "*",
                "clientType": 0,
                "portSecure": 1,
                "rootSquash": 1,
                "squash": 1
            },
            "fileSystemName": "fileset_mount_202207251733",
            "type": 1
        }
    ],
    "performance": {}
    })";
    return buildIndexJob;
}

static AppProtect::SubJob GetSubJob()
{
    AppProtect::SubJob subJob;
    subJob.jobId = "jobId123";
    subJob.subJobId = "subJob123";
    subJob.jobName = "subJob";
    subJob.jobPriority = 1;
    subJob.ignoreFailed = true;
    subJob.execNodeId = "abcde";
    subJob.jobInfo = "{\"ControlFile\":\"/cache/livemount-job/scan/ctrl\","
                    "\"SubTaskType\":1,"
                    "\"Ext\":\"abc\"}";
    return subJob;
}

void ObjectStorageIndexJobTest::SetJobInfo()
{
    AppProtect::BuildIndexJob indexJob = BuildIndexJobSetup();
    auto jobInfoIndex = make_shared<JobCommonInfo>(make_shared<BuildIndexJob>(indexJob));
    m_indexObj.SetJobInfo(jobInfoIndex);
}

void ObjectStorageIndexJobTest::SetIncJobInfo()
{
    AppProtect::BuildIndexJob indexJob = BuildIndexJobSetupInc();
    auto jobInfoIndex = make_shared<JobCommonInfo>(make_shared<BuildIndexJob>(indexJob));
    m_indexObj.SetJobInfo(jobInfoIndex);
}

static void Stub_AddReturnValue_SUCCESS(ActionResult& returnValue, const std::vector<AppProtect::SubJob>& obj)
{
    returnValue.code = Module::SUCCESS;
}

static bool StubCheckDcacheExist(string s1)
{
    return true;
}

static void StubFunctionVoid()
{
}

static std::shared_ptr<BuildIndexJob> GetJobInfoBody_nullptr()
{
    return nullptr;
}

static void ReturnVoidStub(int* obj)
{
    return;
}

static void AddNewJobStub(ActionResult& returnValue, const std::vector<SubJob>& job)
{
    returnValue.code = Module::SUCCESS;
}

static void AddNewJobStubFail(ActionResult& returnValue, const std::vector<SubJob>& job)
{
    returnValue.code = Module::FAILED;
}

void ObjectStorageIndexJobTest::SetUp()
{
    stub.set(sleep, ReturnVoidStub);
    stub.set(ADDR(JobService, ReportJobDetails), StubFunctionVoid);
}

void ObjectStorageIndexJobTest::TearDown()
{
}

TEST_F(ObjectStorageIndexJobTest, testPrerequisiteJobInner)
{
    SetJobInfo();
    EXPECT_EQ(m_indexObj.PrerequisiteJob(), Module::SUCCESS);
}

TEST_F(ObjectStorageIndexJobTest, testPrerequisiteJobInnerNullptr)
{
    SetJobInfo();
    stub.set(ADDR(ObjectStorageIndexJob, GetJobInfoBody), GetJobInfoBody_nullptr);
    EXPECT_EQ(m_indexObj.PrerequisiteJob(), Module::FAILED);
}

TEST_F(ObjectStorageIndexJobTest, testGenerateSubJob)
{
    SetJobInfo();
    stub.set(ADDR(JobService, AddNewJob), Stub_AddReturnValue_SUCCESS);

    EXPECT_EQ(m_indexObj.GenerateSubJob(), Module::SUCCESS);
}

TEST_F(ObjectStorageIndexJobTest, testGenerateSubJobNullptr)
{
    SetJobInfo();
    stub.set(ADDR(JobService, AddNewJob), Stub_AddReturnValue_SUCCESS);
    stub.set(ADDR(ObjectStorageIndexJob, GetJobInfoBody), GetJobInfoBody_nullptr);
    EXPECT_EQ(m_indexObj.GenerateSubJob(), Module::FAILED);
}

static void ReportJobReturnVoidStub(ActionResult& returnValue, const SubJobDetails& jobInfo)
{
    returnValue.code = 0;
    return;
}

void ReportJobStub(SubJobStatus::type status)
{
    return;
}

static void StubFunc_SUCCESS()
{
    return;
}

TEST_F(ObjectStorageIndexJobTest, testGenerateSubJobInner)
{
    MOCKER_CPP(&JobService::AddNewJob)
        .stubs()
        .will(invoke(StubFunc_SUCCESS));
    MOCKER_CPP(&JobService::ReportJobDetails)
            .stubs()
            .will(invoke(StubFunc_SUCCESS));
    BuildIndexJob buildIndexJob;
    buildIndexJob.requestId = "reqId123";
    buildIndexJob.jobId = "jId123";

    m_indexObj.m_indexPara = std::make_shared<AppProtect::BuildIndexJob>(buildIndexJob);
    EXPECT_EQ(m_indexObj.GenerateSubJobInner(), Module::SUCCESS);
}

static int StubIdentifyRepos()
{
    return Module::FAILED;
}
static int StubIdentifyReposSuccess()
{
    return Module::SUCCESS;
}

static int StubProcessFullObsIndexSuccess()
{
    return Module::SUCCESS;
}

TEST_F(ObjectStorageIndexJobTest, IdentifyRepos)
{
    SetJobInfo();
    m_indexObj.PrerequisiteJob();
    m_indexObj.m_cacheRepo = std::make_shared<AppProtect::StorageRepository>();
    m_indexObj.m_metaRepo = std::make_shared<AppProtect::StorageRepository>();
    m_indexObj.m_preMetaRepo = std::make_shared<AppProtect::StorageRepository>();
    std::vector<std::string> tpath = {"/home"};
    m_indexObj.m_cacheRepo->path = tpath;
    m_indexObj.m_metaRepo->path = tpath;
    m_indexObj.m_preMetaRepo->path = tpath;
    EXPECT_EQ(m_indexObj.IdentifyRepos(), Module::SUCCESS);
}

TEST_F(ObjectStorageIndexJobTest, ExecuteSubJobInner)
{
    SetJobInfo();
    MOCKER_CPP(&JobService::ReportJobDetails)
            .stubs()
            .will(invoke(StubFunc_SUCCESS));
    MOCKER_CPP(&ObjectStorageIndexJob::IdentifyRepos)
        .stubs()
        .will(returnValue(Module::FAILED))
        .then(returnValue(Module::SUCCESS));
    MOCKER_CPP(&ObjectStorageIndexJob::ProcessFullObsIndex)
        .stubs()
        .will(returnValue(Module::SUCCESS));
    MOCKER_CPP(&ObjectStorageIndexJob::ProcessIncObsIndex)
        .stubs()
        .will(returnValue(Module::SUCCESS));
    EXPECT_EQ(m_indexObj.ExecuteSubJobInner(), Module::FAILED);
    m_indexObj.m_indexType = OBSIndexJobType::OBS_INDEX_TYPE_FULL;
    EXPECT_EQ(m_indexObj.ExecuteSubJobInner(), Module::SUCCESS);
    m_indexObj.m_indexType = OBSIndexJobType::OBS_INDEX_TYPE_INC;
    EXPECT_EQ(m_indexObj.ExecuteSubJobInner(), Module::SUCCESS);
}

TEST_F(ObjectStorageIndexJobTest, IdentifyRepo)
{
    SetJobInfo();
    StorageRepository repo;
    repo.repositoryType = RepositoryDataType::type::CACHE_REPOSITORY;
    EXPECT_EQ(m_indexObj.IdentifyRepo(repo), Module::SUCCESS);
    repo.repositoryType = RepositoryDataType::type::INDEX_REPOSITORY;
    EXPECT_EQ(m_indexObj.IdentifyRepo(repo), Module::SUCCESS);
}

static void StubRemove()
{}

TEST_F(ObjectStorageIndexJobTest, PrepareForGenrateRfi)
{
    SetJobInfo();

    stub.set(OBSPlugin::Remove, StubRemove);
    stub.set(OBSPlugin::CreateDirectory, StubRemove);
    stub.set(OBSPlugin::Remove, StubRemove);

    m_indexObj.m_cacheRepo = std::make_shared<AppProtect::StorageRepository>();
    m_indexObj.m_metaRepo = std::make_shared<AppProtect::StorageRepository>();
    m_indexObj.m_preMetaRepo = std::make_shared<AppProtect::StorageRepository>();
    std::vector<std::string> tpath = {"111"};
    m_indexObj.m_cacheRepo->path = tpath;
    m_indexObj.m_metaRepo->path = tpath;
    m_indexObj.m_preMetaRepo->path = tpath;
    BackupObjectInfosInCopy extendInfo {};
    m_indexObj.m_backupObjectInfosInCopy = std::make_shared<BackupObjectInfosInCopy>(extendInfo);

    std::vector<PrefixInfo> prefix_esn1 {
            {"bucket1", "/opt/aa", {}, true},
            {"bucket2", "/opt/aa", {"11/44"}, false}
    };
    BackupObjectInfo obj1;
    obj1.esn = "esn1";
    obj1.prefixInfo = std::move(prefix_esn1);

    m_indexObj.m_backupObjectInfosInCopy->objectInfos.push_back(obj1);
    string preMetaFilePath = "";
    string curMetafilepath = "222";
    AppProtect::SubJob subJob = GetSubJob();
    m_indexObj.SetSubJob(std::make_shared<SubJob>(subJob));
    EXPECT_NO_THROW(m_indexObj.PrepareForGenrateRfi(preMetaFilePath, curMetafilepath));

    preMetaFilePath = "111";
    EXPECT_NO_THROW(m_indexObj.PrepareForGenrateRfi(preMetaFilePath, curMetafilepath));
}

TEST_F(ObjectStorageIndexJobTest, GeneratedCopyCtrlFileCb)
{
    string str1 = "111";
    string str2 = "2222";
    RfiCbStruct cbParam;

    m_indexObj.GeneratedCopyCtrlFileCb(&str1, str2);
    m_indexObj.GeneratedHardLinkCtrlFileCb(&str1, str2);
    EXPECT_NO_THROW(m_indexObj.GenerateRfiCtrlFileCb(&str1, cbParam));

    cbParam.isFailed = false;
    cbParam.isComplete = true;
    EXPECT_NO_THROW(m_indexObj.GenerateRfiCtrlFileCb(&str1, cbParam));

    cbParam.isComplete = false;
    EXPECT_NO_THROW(m_indexObj.GenerateRfiCtrlFileCb(&str1, cbParam));
}

static void StubPrepareForGenerateRfi(ObjectStorageIndexJob* obj, string s1, string s2)
{
    obj->m_isPreparing = false;
}

TEST_F(ObjectStorageIndexJobTest, testExecuteSubJob)
{
    SetJobInfo();
    stub.set(ADDR(ObjectStorageIndexJob, PrepareForGenrateRfi), StubPrepareForGenerateRfi);
    stub.set(ADDR(ObjectStorageIndexJob, CheckDcacheExist), StubCheckDcacheExist);
    stub.set(ADDR(ScanMgr, CreateScanInst), CreateScanInstStub);
    stub.set(ADDR(ObjectStorageIndexJob, IdentifyRepos), StubIdentifyReposSuccess);
    stub.set(ADDR(ObjectStorageIndexJob, ProcessFullObsIndex), StubProcessFullObsIndexSuccess);

    AppProtect::SubJob subJob = GetSubJob();
    m_indexObj.SetSubJob(std::make_shared<SubJob>(subJob));
    EXPECT_EQ(m_indexObj.ExecuteSubJob(), Module::SUCCESS);
}

TEST_F(ObjectStorageIndexJobTest, testCheckAllBucketsDcacheExist)
{
    string path = "/MetaFS/cache";
    stub.set(ADDR(ObjectStorageIndexJob, CheckDcacheExist), StubCheckDcacheExist);
    BackupObjectInfosInCopy extendInfo {};
    m_indexObj.m_backupObjectInfosInCopy = std::make_shared<BackupObjectInfosInCopy>(extendInfo);
    std::vector<PrefixInfo> prefix_esn1 {
            {"bucket1", "/opt/aa", {}, true},
            {"bucket2", "/opt/aa", {"11/44"}, false}
    };
    BackupObjectInfo obj1;
    obj1.esn = "esn1";
    obj1.prefixInfo = std::move(prefix_esn1);
    m_indexObj.m_backupObjectInfosInCopy->objectInfos.emplace_back(obj1);
    EXPECT_EQ(m_indexObj.CheckAllBucketsDcacheExist(path), true);
}

static bool IsFileExistSuccess(const std::string& fileName)
{
    return true;
}

static bool IsFileExistFailed(const std::string& fileName)
{
    return false;
}

TEST_F(ObjectStorageIndexJobTest, testCheckDcacheExist)
{
    string path = "/MetaFS/cache";
    stub.set(IsFileExist, IsFileExistSuccess);
    EXPECT_EQ(m_indexObj.CheckDcacheExist(path), true);
}

static bool StubCheckAllBucketsDcacheExistFalse(string metaFilePath)
{
    return false;
}

TEST_F(ObjectStorageIndexJobTest, testProcessFullObsIndexFail)
{
    SetJobInfo();
    m_indexObj.m_cacheRepo = std::make_shared<AppProtect::StorageRepository>();
    m_indexObj.m_metaRepo = std::make_shared<AppProtect::StorageRepository>();
    m_indexObj.m_preMetaRepo = std::make_shared<AppProtect::StorageRepository>();
    std::vector<std::string> tpath = {"111"};
    m_indexObj.m_cacheRepo->path = tpath;
    m_indexObj.m_metaRepo->path = tpath;
    m_indexObj.m_preMetaRepo->path = tpath;
    BackupObjectInfosInCopy extendInfo {};
    m_indexObj.m_backupObjectInfosInCopy = std::make_shared<BackupObjectInfosInCopy>(extendInfo);
    m_indexObj.m_isPreparing = false;

    MOCKER_CPP(&ObjectStorageIndexJob::ReportJob)
        .stubs()
        .will(ignoreReturnValue());
    MOCKER_CPP(&ObjectStorageIndexJob::CheckAllBucketsDcacheExist)
        .stubs()
        .will(returnValue(false))
        .then(returnValue(true));
    MOCKER_CPP(&ObjectStorageIndexJob::GenerateAllBucketsFullRfiInPath)
        .stubs()
        .will(returnValue(Module::FAILED))
        .then(returnValue(Module::SUCCESS));
    EXPECT_EQ(m_indexObj.ProcessFullObsIndex(), Module::SUCCESS);
}

TEST_F(ObjectStorageIndexJobTest, ProcessIncHostIndexForPrefix)
{
    SetJobInfo();
    MOCKER_CPP(&ObjectStorageIndexJob::MonitorScanner)
        .stubs()
        .will(returnValue(SCANNER_STATUS::COMPLETED));
    MOCKER_CPP(&ObjectStorageIndexJob::StartScanner)
        .stubs()
        .will(returnValue(true));
    MOCKER_CPP(&ObjectStorageIndexJob::FillScanConfigForGenerateRfi)
        .stubs()
        .will(ignoreReturnValue());
        
    m_indexObj.m_cacheRepo = std::make_shared<AppProtect::StorageRepository>();
    m_indexObj.m_metaRepo = std::make_shared<AppProtect::StorageRepository>();
    m_indexObj.m_preMetaRepo = std::make_shared<AppProtect::StorageRepository>();
    std::vector<std::string> tpath = {"/home"};
    m_indexObj.m_cacheRepo->path = tpath;
    m_indexObj.m_metaRepo->path = tpath;
    m_indexObj.m_preMetaRepo->path = tpath;
    BackupObjectInfosInCopy extendInfo {};
    m_indexObj.m_backupObjectInfosInCopy = std::make_shared<BackupObjectInfosInCopy>(extendInfo);
    std::vector<string> curDirList = {"/home/cur1", "/home/cur2", "/home/cur6"};
    std::vector<string> prevDirList = {"/home/cur1", "/home/cur3", "/home/cur4","/home/cur8"};
    EXPECT_EQ(m_indexObj.ProcessIncHostIndexForPrefix(curDirList, prevDirList), Module::SUCCESS);
    EXPECT_EQ(m_indexObj.ProcessIncHostIndexForPrefix(prevDirList, curDirList), Module::SUCCESS);
}

static int StubGenerateFullRfiInPathSuccess(const string& path, bool isPre)
{
    return Module::SUCCESS;
}

TEST_F(ObjectStorageIndexJobTest, tesGenerateAllBucketsFullRfiInPath)
{
    SetJobInfo();
    m_indexObj.m_cacheRepo = std::make_shared<AppProtect::StorageRepository>();
    m_indexObj.m_metaRepo = std::make_shared<AppProtect::StorageRepository>();
    m_indexObj.m_preMetaRepo = std::make_shared<AppProtect::StorageRepository>();
    std::vector<std::string> tpath = {"111"};
    m_indexObj.m_cacheRepo->path = tpath;
    m_indexObj.m_metaRepo->path = tpath;
    m_indexObj.m_preMetaRepo->path = tpath;
    BackupObjectInfosInCopy extendInfo {};
    m_indexObj.m_backupObjectInfosInCopy = std::make_shared<BackupObjectInfosInCopy>(extendInfo);
    std::vector<PrefixInfo> prefix_esn1 {
            {"bucket1", "/opt/aa", {}, true},
            {"bucket2", "/opt/aa", {"11/44"}, false}
    };
    BackupObjectInfo obj1;
    obj1.esn = "esn1";
    obj1.prefixInfo = std::move(prefix_esn1);
    m_indexObj.m_backupObjectInfosInCopy->objectInfos.push_back(obj1);
    stub.set(ADDR(ObjectStorageIndexJob, GenerateFullRfiInPath), StubGenerateFullRfiInPathSuccess);

    EXPECT_EQ(m_indexObj.GenerateAllBucketsFullRfiInPath(), Module::FAILED);
}

TEST_F(ObjectStorageIndexJobTest, testProcessIncObsIndex)
{
    SetJobInfo();
    MOCKER_CPP(&ObjectStorageIndexJob::CheckAllBucketsDcacheExist)
        .stubs()
        .will(returnValue(false))
        .then(returnValue(true));
    MOCKER_CPP(&OBSPlugin::CheckUnzipMetafileSucceed)
        .stubs()
        .will(returnValue(true));
    m_indexObj.m_cacheRepo = std::make_shared<AppProtect::StorageRepository>();
    m_indexObj.m_metaRepo = std::make_shared<AppProtect::StorageRepository>();
    m_indexObj.m_preMetaRepo = std::make_shared<AppProtect::StorageRepository>();
    std::vector<std::string> tpath = {"/home"};
    m_indexObj.m_cacheRepo->path = tpath;
    m_indexObj.m_metaRepo->path = tpath;
    m_indexObj.m_preMetaRepo->path = tpath;
    BackupObjectInfosInCopy extendInfo {};
    m_indexObj.m_backupObjectInfosInCopy = std::make_shared<BackupObjectInfosInCopy>(extendInfo);
    stub.set(OBSPlugin::GetDirListInDirectory, GetDirListInDirectoryStub_Succ);
    
    MOCKER_CPP(&ObjectStorageIndexJob::ProcessIncHostIndexForPrefix)
        .stubs()
        .will(returnValue(Module::SUCCESS));
    EXPECT_EQ(m_indexObj.ProcessIncObsIndex(), Module::SUCCESS);
    EXPECT_EQ(m_indexObj.ProcessIncObsIndex(), Module::SUCCESS);
}

TEST_F(ObjectStorageIndexJobTest, testUnzipPreMetafileToWorkDir)
{
    string workDir = "/home";
    MOCKER(OBSPlugin::CreateDirectory)
        .stubs()
        .will(returnValue(true));
    MOCKER_CPP(&OBSPlugin::CheckUnzipMetafileSucceed)
        .stubs()
        .will(returnValue(true));
    m_indexObj.m_cacheRepo = std::make_shared<AppProtect::StorageRepository>();
    m_indexObj.m_metaRepo = std::make_shared<AppProtect::StorageRepository>();
    m_indexObj.m_preMetaRepo = std::make_shared<AppProtect::StorageRepository>();
    std::vector<std::string> tpath = {"/home"};
    m_indexObj.m_cacheRepo->path = tpath;
    m_indexObj.m_metaRepo->path = tpath;
    m_indexObj.m_preMetaRepo->path = tpath;
    EXPECT_EQ(m_indexObj.UnzipPreMetafileToWorkDir(workDir), true);
}

static string StubPrepareUnZipCommand(const string &workDir, const string &dcache,
    const string &fcache, const string &meta, const string &xmeta)
{
    return "ls";
}

static bool StubCheckUnzipMetafileSucceed(const string& execCmd, const string& workDir)
{
    return true;
}

TEST_F(ObjectStorageIndexJobTest, testUnzipCurMetafileToWorkDir)
{
    string workDir = "index";
    SetJobInfo();
    m_indexObj.m_cacheRepo = std::make_shared<AppProtect::StorageRepository>();
    m_indexObj.m_metaRepo = std::make_shared<AppProtect::StorageRepository>();
    m_indexObj.m_preMetaRepo = std::make_shared<AppProtect::StorageRepository>();
    std::vector<std::string> tpath = {"/home"};
    m_indexObj.m_cacheRepo->path = tpath;
    m_indexObj.m_metaRepo->path = tpath;
    m_indexObj.m_preMetaRepo->path = tpath;
    BackupObjectInfosInCopy extendInfo {};
    m_indexObj.m_backupObjectInfosInCopy = std::make_shared<BackupObjectInfosInCopy>(extendInfo);

    stub.set(ADDR(OBSPlugin, PrepareUnZipCommand), StubPrepareUnZipCommand);
    stub.set(ADDR(OBSPlugin, CheckUnzipMetafileSucceed), StubCheckUnzipMetafileSucceed);
    EXPECT_EQ(m_indexObj.UnzipCurMetafileToWorkDir(workDir), true);
}

TEST_F(ObjectStorageIndexJobTest, UnzipMetafileToCurPathAndRemoveAsync)
{
    MOCKER(Module::runShellCmdWithOutput)
        .stubs()
        .will(returnValue(1));
    string workDir = "index";
    SetJobInfo();
    m_indexObj.m_cacheRepo = std::make_shared<AppProtect::StorageRepository>();
    m_indexObj.m_metaRepo = std::make_shared<AppProtect::StorageRepository>();
    m_indexObj.m_preMetaRepo = std::make_shared<AppProtect::StorageRepository>();
    std::vector<std::string> tpath = {"/home"};
    m_indexObj.m_cacheRepo->path = tpath;
    m_indexObj.m_metaRepo->path = tpath;
    m_indexObj.m_preMetaRepo->path = tpath;
    BackupObjectInfosInCopy extendInfo {};
    m_indexObj.m_backupObjectInfosInCopy = std::make_shared<BackupObjectInfosInCopy>(extendInfo);
    promise<int> result;
    EXPECT_NO_THROW(m_indexObj.UnzipMetafileToCurPathAndRemoveAsync("/home",result));
}
